/*
 * NetworkManager.cpp
 *
 *  Created on: Dec 11, 2014
 *      Author: toti
 */

#include <Network/IBRCNetworkManager.hpp>

IBRCNetworkManager::IBRCNetworkManager(ConnectionManager *connectionManager) {

	this->connectionManager = connectionManager;

	defaultNickNumber = 0;
	requestIdNumber = 0;

	networkServerList = new std::list<NetworkServer*>();
	networkClientList = new std::list<NetworkClient*>();
	networkChannelList = new std::list<NetworkChannel*>();
	networkRequestList = new std::list<NetworkRequest*>();

}

void IBRCNetworkManager::processData() {

	MessagePackage* inboundMessagePackage = 0;

	/* Get incoming MessagePackage from inbound fifo */
	while ((inboundMessagePackage = connectionManager->popInboundMessagePackageList())) {

		/* Process MessagePackage depending on message type */
		switch (inboundMessagePackage->getMessagePackageType()) {

		case MessagePackage::CLIENT_MESSAGE_PACKAGE:

			/* Message from connected client */
			processClientMessagePackage((ClientMessagePackage*) inboundMessagePackage);
			break;

		case MessagePackage::SERVER_MESSAGE_PACKAGE:

			/* Message from connected server */
			processServerMessagePackage((ServerMessagePackage*) inboundMessagePackage);
			break;

		}

		delete (inboundMessagePackage);

	}

}

/***********************************************************************************
 ***********************************************************************************
 *
 * Server Handler:
 *
 * 	Handler functions for server messages
 *
 *
 *
 ***********************************************************************************
 ***********************************************************************************/

void IBRCNetworkManager::processServerMessagePackage(ServerMessagePackage *serverMessagePackage) {

	/*
	 * Process ServerMessagePackage dependent on it's type
	 */
	switch (serverMessagePackage->getMessagePackageType()) {

	case ServerMessagePackage::TYPE_SERVER_REGISTRATION:

		processServerRegistration(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_NICK_REMOVE:

		processServerNickRemove(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_CHANNEL_JOIN:

		processServerChannelJoin(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_CHANNEL_LEAVE:

		processServerChannelLeave(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_CHANNEL_SETTOPIC:

		processServerChannelSetTopic(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_CHANNEL_MESSAGE:

		processServerChannelMessage(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_CHANNEL_PRIVMESSAGE:

		processServerChannelPrivateMessage(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_REQUEST_NICK_CREATE:

		processServerRequestNickCreate(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_REQUEST_CHANNEL_CREATE:

		processServerRequestChannelCreate(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_REQUEST_CHANNEL_REMOVE:

		processServerRequestChannelRemove(serverMessagePackage);
		break;

	case ServerMessagePackage::TYPE_RESPONSE:

		processServerResponse(serverMessagePackage);
		break;

	}
}

void IBRCNetworkManager::processServerRegistration(ServerMessagePackage *package) {

	/* Check if sender requests a list of currently available server */
	std::string& serverListRequested = package->getParameter(ServerMessagePackage::SERVER_REGISTRATION_REQUEST_SERVERLIST);

	/* Get LocalNode of sender server */
	LocalServer *localServer = (LocalServer*) package->getLocalNode();

	/* Deploy server list if requested */
	if (!serverListRequested.compare("true")) {

		/* Deploy ourself */
		ServerMessagePackage *outboundPackage = new ServerMessagePackage(localServer);
		outboundPackage->setMessageType(ServerMessagePackage::TYPE_SERVER_REGISTRATION);
		outboundPackage->setSender(Config::instance()->getServerName());
		outboundPackage->setParameter(ServerMessagePackage::SERVER_REGISTRATION_REQUEST_SERVERLIST, "false");

		connectionManager->pushOutboundMessagePackageList(outboundPackage);

		/* Deploy our server list */
		for (std::list<NetworkServer*>::iterator it = networkServerList->begin(); it != networkServerList->end(); ++it) {

			outboundPackage = new ServerMessagePackage(localServer);
			outboundPackage->setMessageType(ServerMessagePackage::TYPE_SERVER_REGISTRATION);
			outboundPackage->setSender((*it)->getServerName());
			outboundPackage->setParameter(ServerMessagePackage::SERVER_REGISTRATION_REQUEST_SERVERLIST, "false");

			connectionManager->pushOutboundMessagePackageList(outboundPackage);

		}

	}

	/*
	 * Create a new NetworkServer and connect it to the LocalNode we received the registration from
	 * to remember how it is reachable. Add the server to NetworkServerList.
	 */
	NetworkServer *networkServer = new NetworkServer(localServer, package->getSender());
	networkServerList->push_back(networkServer);

	/* Set request parameter to false (prevent message loop) and broadcast package to the other server */
	package->setParameter(ServerMessagePackage::SERVER_REGISTRATION_REQUEST_SERVERLIST, "false");
	performForwardBroadcast(package);
}

void IBRCNetworkManager::processServerNickRemove(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get nickname to remove */
	std::string& clientToRemoveName = package->getParameter(ServerMessagePackage::NICK_REMOVE_NAME);

	/* Get NetworkClient to remove from list */
	NetworkClient *networkClient = findNetworkClientByName(clientToRemoveName);

	/* Find channels where old nick is channel owner and set their owner to null */
	std::list<NetworkChannel*> channelList;
	findNetworkChannelByOwner(&channelList, networkClient);

	for(std::list<NetworkChannel*>::iterator it=channelList.begin(); it!=channelList.end(); ++it){
		(*it)->setChannelOwner(0);
	}

	/* Remove NetworkClient from list and destroy object */
	networkClientList->remove(networkClient);
	delete (networkClient);
}

void IBRCNetworkManager::processServerChannelJoin(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get nickname of NetworkClient and NetworkChannel to join */
	std::string& nickName = package->getParameter(ServerMessagePackage::CHANNEL_JOIN_NICK);
	std::string& channelName = package->getParameter(ServerMessagePackage::CHANNEL_JOIN_NAME);

	/* Find NetworkClient and NetworkChannel */
	NetworkClient *networkClient = findNetworkClientByName(nickName);
	NetworkChannel *networkChannel = findNetworkChannelByName(channelName);

	/* Set channel of NetworkClient */
	networkClient->setNetworkChannel(networkChannel);

}

void IBRCNetworkManager::processServerChannelLeave(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get nickname of NetworkClient to leave his channel */
	std::string& nickName = package->getParameter(ServerMessagePackage::CHANNEL_LEAVE_NICK);

	/* Set NetworkChannel of NetworkClient to null */
	NetworkClient *networkClient = findNetworkClientByName(nickName);
	networkClient->setNetworkChannel(0);

}

void IBRCNetworkManager::processServerChannelSetTopic(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get name and new topic for NetworkChannel */
	std::string& channelName = package->getParameter(ServerMessagePackage::CHANNEL_SETTOPIC_NAME);
	std::string& channelTopic = package->getParameter(ServerMessagePackage::CHANNEL_SETTOPIC_TOPIC);

	/* Set new topic */
	NetworkChannel *networkChannel = findNetworkChannelByName(channelName);
	networkChannel->setTopic(channelTopic);

}

void IBRCNetworkManager::processServerChannelMessage(ServerMessagePackage *package) {

	/* Get required information from ServerMessagePackage */
	std::string& senderServerName = package->getSender();
	std::string& channelName = package->getParameter(ServerMessagePackage::CHANNEL_MESSAGE_NAME);
	std::string& senderName = package->getParameter(ServerMessagePackage::CHANNEL_MESSAGE_SENDER);
	std::string& text = package->getText();

	std::list<NetworkClient*> networkClientList;
	std::list<NetworkServer*> networkServerList;
	std::list<LocalServer*> localServerList;

	/* Get NetworkServer of sender */
	NetworkServer *senderServer = findNetworkServerByName(senderServerName);
	/* Get NetworkChannel of sender */
	NetworkChannel *networkChannel = findNetworkChannelByName(channelName);
	/* Get all NetworkClients assigned to that channel */
	findNetworkClientsByChannel(&networkClientList, networkChannel);
	/* Get all NetworkServer of the NetworkClients to send the message to */
	findNetworkServerByClients(&networkServerList, &networkClientList);
	/* Get all LocalNodes of the NetworkServer to populate the message */
	findLocalServerByNetworkServer(&localServerList, &networkServerList);


	/*
	 * Send the MessagePackage to all localClients except the one we received it from
	 */
	for (std::list<LocalServer*>::iterator it = localServerList.begin(); it != localServerList.end(); ++it) {

		LocalServer *localServer = *it;

		if (localServer && localServer != senderServer->getLocalNode()) {

			ServerMessagePackage *serverMessagePackage = new ServerMessagePackage(localServer);
			*serverMessagePackage = *package;
			serverMessagePackage->setLocalNode(localServer);

			connectionManager->pushOutboundMessagePackageList(serverMessagePackage);

		}

	}


	/*
	 * Send the Message to all clients connected to our server and assigned to the channel
	 */
	std::list<LocalNode*> *localClientList = connectionManager->getLocalClientList();

	for (std::list<LocalNode*>::iterator it = localClientList->begin(); it != localClientList->end(); ++it) {

		LocalClient *localClient = (LocalClient*) *it;

		if (localClient->getNetworkClient()->getNetworkChannel() == networkChannel) {

			/*
			 * Inform localClient
			 */
			std::string clientText;
			std::ostringstream clientTextStream;
			clientTextStream << senderName << ":> " << text << std::endl;
			clientText = clientTextStream.str();

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

		}

	}

}

void IBRCNetworkManager::processServerChannelPrivateMessage(ServerMessagePackage *package) {

	/* Get required information from ServerMessagePackage */
	std::string& destinationName = package->getParameter(ServerMessagePackage::CHANNEL_PRIVMESSAGE_NAME);
	std::string& senderName = package->getParameter(ServerMessagePackage::CHANNEL_PRIVMESSAGE_SENDER);
	std::string& text = package->getText();

	/* Get destination NetworkClient and NetworkServer */
	NetworkClient *destinationNetworkClient = findNetworkClientByName(destinationName);
	NetworkServer *destinationNetworkServer = destinationNetworkClient->getNetworkServer();

	/*
	 * Distinguish between locally connected and remote connected client
	 */
	if (destinationNetworkServer == 0) {

		/*
		 * Destination client is connected to this server
		 */
		std::list<LocalNode*> *localClientList = connectionManager->getLocalClientList();

		for (std::list<LocalNode*>::iterator it = localClientList->begin(); it != localClientList->end(); ++it) {

			LocalClient *localClient = (LocalClient*) *it;

			if (localClient->getNetworkClient() == destinationNetworkClient) {

				/*
				 * Inform localClient
				 */
				std::string clientText;
				std::ostringstream clientTextStream;
				clientTextStream << senderName << " PRIVAT :> " << text << std::endl;
				clientText = clientTextStream.str();

				ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
				clientMessagePackage->setText(clientText);

				connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

			}

		}

	} else {

		/*
		 * Destination client is connected to a different server than this one,
		 * forward message into destination clients server direction
		 */

		LocalServer *localServer = (LocalServer*) destinationNetworkServer->getLocalNode();

		ServerMessagePackage *serverMessagePackage = new ServerMessagePackage(localServer);
		*serverMessagePackage = *package;
		serverMessagePackage->setLocalNode(localServer);

		connectionManager->pushOutboundMessagePackageList(serverMessagePackage);

	}

}

void IBRCNetworkManager::processServerRequestNickCreate(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get required information from ServerMessagePackage */
	std::string& requestedNick = package->getParameter(ServerMessagePackage::REQUEST_NICK_CREATE_NAME);
	std::string& requestId = package->getParameter(ServerMessagePackage::REQUEST_NICK_CREATE_ID);

	/*
	 * Generate our response. Positive or negative result depending on
	 * the fact that we already have a pending request for this nick or not.
	 */
	bool requestAccepted = true;

	/* Check the existing clients */
	if (findNetworkClientByName(requestedNick)) {
		requestAccepted = false;
	}

	/* Check the pending requests for the requested nick */
	if (findCreateNickNetworkRequestByName(requestedNick)) {
		requestAccepted = false;
	}

	/* Add the request to our request list */
	CreateNickNetworkRequest *request = new CreateNickNetworkRequest();
	request->setRequestedNick(requestedNick);
	request->setRequestId(requestId);
	request->setSender(package->getSender());
	request->setVoters(networkServerList->size() + 1);
	request->addResponse(requestAccepted);

	networkRequestList->push_back(request);

	/* Broadcast a response with our answer */
	performResponse(requestId, requestAccepted);


	/*
	 * Tell ConnectionManager to decline new server connections
	 */
	connectionManager->stopServerListening();

}

void IBRCNetworkManager::processServerRequestChannelCreate(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get required information from ServerMessagePackage */
	std::string& requestId = package->getParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_ID);
	std::string& requestedChannelName = package->getParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_NAME);
	std::string& requestedChannelOwner = package->getParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_OWNER);

	/*
	 * Generate our response. Positive or negative result depending on
	 * the fact that we already have a pending request for this nick or not.
	 */
	bool requestAccepted = true;

	/* Check the existing clients */
	if (findNetworkChannelByName(requestedChannelName)) {
		requestAccepted = false;
	}

	/* Check the pending requests for the requested nick */
	if (findCreateChannelNetworkRequestByName(requestedChannelName)) {
		requestAccepted = false;
	}

	/* Add the request to our request list */
	CreateChannelNetworkRequest *request = new CreateChannelNetworkRequest();
	request->setRequestId(requestId);
	request->setRequestedChannelName(requestedChannelName);
	request->setRequestedChannelOwner(requestedChannelOwner);
	request->setSender(package->getSender());
	request->setVoters(networkServerList->size() + 1);
	request->addResponse(requestAccepted);

	networkRequestList->push_back(request);

	/* Broadcast a response with our answer */
	performResponse(requestId, requestAccepted);

}

void IBRCNetworkManager::processServerRequestChannelRemove(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get required information from ServerMessagePackage */
	std::string& requestId = package->getParameter(ServerMessagePackage::REQUEST_CHANNEL_REMOVE_ID);
	std::string& requestedChannelName = package->getParameter(ServerMessagePackage::REQUEST_CHANNEL_REMOVE_NAME);

	/*
	 * Generate our response. Positive or negative result depending on
	 * the fact that we already have a pending request for this nick or not.
	 */
	bool requestAccepted = true;

	NetworkChannel *networkChannel = findNetworkChannelByName(requestedChannelName);

	std::list<NetworkClient*> clientList;
	findNetworkClientsByChannel(&clientList, networkChannel);

	if (clientList.size() > 0) {
		requestAccepted = false;
	}

	/* Add the request to our request list */
	RemoveChannelNetworkRequest *request = new RemoveChannelNetworkRequest();
	request->setRequestId(requestId);
	request->setSender(package->getSender());
	request->setChannelName(requestedChannelName);
	request->setVoters(networkServerList->size() + 1);
	request->addResponse(requestAccepted);

	networkRequestList->push_back(request);

	/* Broadcast a response with our answer */
	performResponse(requestId, requestAccepted);

}

void IBRCNetworkManager::processServerResponse(ServerMessagePackage *package) {

	/* Forward the request by broadcasting it to the other server */
	performForwardBroadcast(package);

	/* Get NetworkRequest from list and add the received response value */
	NetworkRequest *networkRequest = findNetworkRequestById(package->getParameter(0));
	networkRequest->addResponse(package->getParameter(ServerMessagePackage::RESPONSE_VALUE));

	/* Check if every server responded and request can be evaluated */
	switch (networkRequest->getRequestState()) {

	case NetworkRequest::ACCEPTED:
		processServerRequestAccepted(networkRequest);
		break;
	case NetworkRequest::REJECTED:
		processServerRequestRejected(networkRequest);
		break;
	case NetworkRequest::UNDECIDED:
		break;

	}

}

void IBRCNetworkManager::processServerRequestAccepted(NetworkRequest *networkRequest) {

	/*
	 * Check which request type was accepted
	 */
	switch (networkRequest->getNetworkRequestType()) {

	case NetworkRequest::NICK_REQUEST: {

		/* Get required information from NetworkRequest */
		CreateNickNetworkRequest *createNickNetworkRequest = (CreateNickNetworkRequest*) networkRequest;
		LocalClient *localClient = createNickNetworkRequest->getLocalClient();

		/* Create a new NetworkClient */
		NetworkClient *newNetworkClient = new NetworkClient();
		newNetworkClient->setClientName(createNickNetworkRequest->getRequestedNick());
		newNetworkClient->setNetworkServer(findNetworkServerByName(createNickNetworkRequest->getSender()));

		networkClientList->push_back(newNetworkClient);

		/* Check if the request was initiated by a LocalClient of our server*/
		if (localClient) {

			/*
			 * Inform localClient
			 */
			std::string clientText;
			std::ostringstream clientTextStream;
			clientTextStream << "Server:> New nickname: " << createNickNetworkRequest->getRequestedNick() << std::endl;
			clientText = clientTextStream.str();

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

			/*
			 * Update LocalClients NetworkClient and delete the old one
			 */
			NetworkClient *oldNetworkClient = localClient->getNetworkClient();

			if (oldNetworkClient) {

				ServerMessagePackage serverMessagePackage(0);
				serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_NICK_REMOVE);
				serverMessagePackage.setSender(Config::instance()->getServerName());
				serverMessagePackage.setParameter(ServerMessagePackage::NICK_REMOVE_NAME, oldNetworkClient->getClientName());

				performCompleteBroadcast(&serverMessagePackage);

				/* Find channels where old nick ist owner and set their owner to null */
				std::list<NetworkChannel*> channelList;
				findNetworkChannelByOwner(&channelList, oldNetworkClient);

				for(std::list<NetworkChannel*>::iterator it=channelList.begin(); it!=channelList.end(); ++it){
					(*it)->setChannelOwner(0);
				}

				networkClientList->remove(oldNetworkClient);
				delete (oldNetworkClient);

				localClient->setNetworkClient(newNetworkClient);

			} else {

				localClient->setNetworkClient(newNetworkClient);
			}

			localClient->setNetworkClient(newNetworkClient);

		}

		break;
	}
	case NetworkRequest::CHANNEL_CREATE_REQUEST: {

		/* Get required information from NetworkRequest */
		CreateChannelNetworkRequest *createChannelNetworkRequest = (CreateChannelNetworkRequest*) networkRequest;
		LocalClient *localClient = createChannelNetworkRequest->getLocalClient();

		/* Create new network channel */
		NetworkChannel *newNetworkChannel = new NetworkChannel();
		newNetworkChannel->setChannelName(createChannelNetworkRequest->getRequestedChannelName());
		newNetworkChannel->setChannelOwner(findNetworkClientByName(createChannelNetworkRequest->getRequestedChannelOwner()));

		networkChannelList->push_back(newNetworkChannel);

		/* Save old channel temporary and switch to new one */
		NetworkChannel *oldNetworkChannel;
		NetworkClient *networkClient = findNetworkClientByName(createChannelNetworkRequest->getRequestedChannelOwner());
		oldNetworkChannel = networkClient->getNetworkChannel();
		networkClient->setNetworkChannel(newNetworkChannel);

		/* Check if the request was initiated by a localClient of our server*/
		if (localClient) {

			/*
			 * Inform localClient
			 */
			std::string clientText;
			std::ostringstream clientTextStream;
			clientTextStream << "Server:> Created channel: " << createChannelNetworkRequest->getRequestedChannelName() << std::endl;
			clientText = clientTextStream.str();

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

			performChannelRemoveIfEmpty(localClient, oldNetworkChannel);

		}

		break;
	}
	case NetworkRequest::CHANNEL_REMOVE_REQUEST: {

		/* Simply remove NetworkChannel */
		RemoveChannelNetworkRequest *removeChannelNetworkRequest = (RemoveChannelNetworkRequest*) networkRequest;
		NetworkChannel *networkChannel = findNetworkChannelByName(removeChannelNetworkRequest->getChannelName());
		networkChannelList->remove(networkChannel);
		delete (networkChannel);

		break;
	}
	}

	/* Clean up */
	networkRequestList->remove(networkRequest);
	delete (networkRequest);

}

void IBRCNetworkManager::processServerRequestRejected(NetworkRequest *networkRequest) {

	/* Get required information from NetworkRequest */
	LocalNode *localNode = (LocalNode*) networkRequest->getLocalClient();


	/*
	 * Check which request type was rejected
	 */
	switch (networkRequest->getNetworkRequestType()) {

	case NetworkRequest::NICK_REQUEST: {

		CreateNickNetworkRequest *createNickNetworkRequest = (CreateNickNetworkRequest*) networkRequest;

		if (localNode) {

			std::string clientText;
			std::ostringstream clientTextStream;
			clientTextStream << "Server:> Fail - Unable to assign nickname: " << createNickNetworkRequest->getRequestedNick() << std::endl;
			clientText = clientTextStream.str();

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localNode);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

		}
		break;
	}
	case NetworkRequest::CHANNEL_CREATE_REQUEST: {

		if (localNode) {

			/*
			 * Request for channel is already pending -> don't send request
			 */
			std::string clientText = "Server:> Fail - channel not ready yet - please try again!\n\r";

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localNode);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);
		}

		break;
	}
	case NetworkRequest::CHANNEL_REMOVE_REQUEST: {

		// Don't do anything

	}
	}

	/* Clean up */
	networkRequestList->remove(networkRequest);
	delete (networkRequest);

}

/***********************************************************************************
 ***********************************************************************************
 *
 * Client Handler:
 *
 * 	Handler functions for client messages
 *
 *
 *
 ***********************************************************************************
 ***********************************************************************************/

void IBRCNetworkManager::processClientMessagePackage(ClientMessagePackage *clientMessagePackage) {

	/*
	 * Process ClientMessagePackage dependent on it's type
	 */
	switch (clientMessagePackage->getMessagePackageType()) {

	case ClientMessagePackage::TYPE_REGISTRATION:

		processClientRegistrationMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_CHANNEL_MESSAGE:

		processClientChannelMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_GETTOPIC_MESSAGE:

		processClientGettopicMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_JOIN_MESSAGE:

		processClientJoinMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_LEAVE_MESSAGE:

		processClientLeaveMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_LIST_MESSAGE:

		processClientListMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_NICK_MESSAGE:

		processClientNickMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_PRIVATE_MESSAGE:

		processClientPrivateMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_QUIT_MESSAGE:

		processClientQuitMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_SETTOPIC_MESSAGE:

		processClientSettopicMessage(clientMessagePackage);
		break;

	case ClientMessagePackage::TYPE_UNDEFINED_MESSAGE:

		break;

	}

}

void IBRCNetworkManager::processClientRegistrationMessage(ClientMessagePackage *package) {

	/* Get LocalClient of sender */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();

	std::string defaultNick;
	std::string requestId;

	/* Generate default nick */
	performGenerateDefaultNick(defaultNick);

	/* Generate request id */
	performGenerateRequestId(requestId);

	/* Create a request and add it to the list of pending requests */
	CreateNickNetworkRequest *createNickNetworkRequest = new CreateNickNetworkRequest();
	createNickNetworkRequest->setRequestedNick(defaultNick);
	createNickNetworkRequest->setRequestId(requestId);
	createNickNetworkRequest->setSender(Config::instance()->getServerName());
	createNickNetworkRequest->setVoters(networkServerList->size() + 1);
	createNickNetworkRequest->setLocalClient(localClient);
	createNickNetworkRequest->addResponse(true);
	networkRequestList->push_back(createNickNetworkRequest);

	/* Create request package for default nick and broadcast it */
	ServerMessagePackage serverMessagePackage(0);
	serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_REQUEST_NICK_CREATE);
	serverMessagePackage.setSender(Config::instance()->getServerName());
	serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_NICK_CREATE_ID, requestId);
	serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_NICK_CREATE_NAME, defaultNick);

	/* Broadcast NICK_CREATE request and our response to this request */
	performCompleteBroadcast(&serverMessagePackage);
	performResponse(requestId, "true");

	/* Send welcome message to client */
	std::string clientText = "Server:> Welcome!\n\r";
	ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
	clientMessagePackage->setText(clientText);

	connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	/* Stop listening for incoming server connections */
	connectionManager->stopServerListening();
}

void IBRCNetworkManager::processClientChannelMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();
	NetworkChannel *networkChannel = networkClient->getNetworkChannel();

	/*
	 * Check if client is assigned to a channel
	 */
	if (networkChannel) {

		/*
		 * Client is assigned to a channel
		 */
		std::string& senderName = networkClient->getClientName();
		std::string& channelName = networkChannel->getChannelName();
		std::string& text = package->getText();

		std::list<NetworkClient*> networkClientList;
		std::list<NetworkServer*> networkServerList;
		std::list<LocalServer*> localServerList;

		/* Get all NetworkClients connected to the channel */
		findNetworkClientsByChannel(&networkClientList, networkChannel);
		/* Get all NetworkServer of the clients */
		findNetworkServerByClients(&networkServerList, &networkClientList);
		/* Get all LocalServer of the NetworkServer */
		findLocalServerByNetworkServer(&localServerList, &networkServerList);

		/*
		 * Send message to all LocalServer
		 */
		for (std::list<LocalServer*>::iterator it = localServerList.begin(); it != localServerList.end(); ++it) {

			LocalServer *localServer = *it;

			ServerMessagePackage *serverMessagePackage = new ServerMessagePackage(localServer);
			serverMessagePackage->setMessageType(ServerMessagePackage::TYPE_CHANNEL_MESSAGE);
			serverMessagePackage->setSender(Config::instance()->getServerName());
			serverMessagePackage->setParameter(ServerMessagePackage::CHANNEL_MESSAGE_NAME, channelName);
			serverMessagePackage->setParameter(ServerMessagePackage::CHANNEL_MESSAGE_SENDER, senderName);
			serverMessagePackage->setText(text);

			connectionManager->pushOutboundMessagePackageList(serverMessagePackage);

		}

		/*
		 * Send message to all LocalClients
		 */
		std::list<LocalNode*> *localClientList = connectionManager->getLocalClientList();

		for (std::list<LocalNode*>::iterator it = localClientList->begin(); it != localClientList->end(); ++it) {

			LocalClient *localClientFromList = (LocalClient*) *it;

			if (localClient != localClientFromList) {

				if (localClientFromList->getNetworkClient()->getNetworkChannel() == networkChannel) {

					/*
					 * Inform localClient
					 */
					std::string clientText;
					std::ostringstream clientTextStream;
					clientTextStream << senderName << ":> " << text << std::endl;
					clientText = clientTextStream.str();

					ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClientFromList);
					clientMessagePackage->setText(clientText);

					connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

				}

			}

		}

	} else {

		/*
		 * Inform LocalClient that he's not assigned to a channel
		 */
		std::string clientText = "Server:> Fail - No channel!\n\r";

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	}
}

void IBRCNetworkManager::processClientGettopicMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();
	NetworkChannel *networkChannel = networkClient->getNetworkChannel();

	std::string clientText;

	/*
	 * Get Topic of channel (if channel is available) and send it to client
	 */
	if (networkChannel) {

		std::ostringstream clientTextStream;
		clientTextStream << "Server:> Topic: " << networkChannel->getTopic() << std::endl;
		clientText = clientTextStream.str();

	} else {
		clientText = "Server:> Fail - No channel!\n\r";
	}

	ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
	clientMessagePackage->setText(clientText);

	connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

}

void IBRCNetworkManager::processClientJoinMessage(ClientMessagePackage *package) {

	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();

	std::string nickName = localClient->getNetworkClient()->getClientName();
	std::string& newChannelName = package->getParameter(ClientMessagePackage::JOIN_CHANNEL_NAME);

	NetworkChannel *newNetworkChannel = findNetworkChannelByName(newChannelName);
	NetworkChannel *oldNetworkChannel = networkClient->getNetworkChannel();

	/*
	 * Check if requested channel is pending to be removed
	 */
	if (!findRemoveChannelNetworkRequestByName(newChannelName)) {

		/*
		 * Join new channel
		 */
		if (newNetworkChannel) {

			/* Channel already exists -> simple join */
			ServerMessagePackage serverMessagePackage(0);
			serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_CHANNEL_JOIN);
			serverMessagePackage.setSender(Config::instance()->getServerName());
			serverMessagePackage.setParameter(ServerMessagePackage::CHANNEL_JOIN_NICK, nickName);
			serverMessagePackage.setParameter(ServerMessagePackage::CHANNEL_JOIN_NAME, newChannelName);

			performCompleteBroadcast(&serverMessagePackage);

			networkClient->setNetworkChannel(newNetworkChannel);

			performChannelRemoveIfEmpty(localClient, oldNetworkChannel);

			/*
			 * Inform localClient
			 */
			std::string clientText;
			std::ostringstream clientTextStream;
			clientTextStream << "Server:> Joined channel: " << newNetworkChannel->getChannelName() << std::endl;
			clientText = clientTextStream.str();

			ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
			clientMessagePackage->setText(clientText);

			connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

		} else {

			/* Channel doesn't exist yet -> Check pending request and send request */
			if (findCreateChannelNetworkRequestByName(newChannelName)) {

				/* Request for channel is already pending -> don't send request */
				std::string clientText = "Server:> Fail - channel not ready yet - please try again!\n\r";

				ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
				clientMessagePackage->setText(clientText);

				connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

			} else {

				/* No Request for channel is pending yet -> send request */

				std::string requestId;
				performGenerateRequestId(requestId);

				/* Create a request and add it to the list of pending requests */
				CreateChannelNetworkRequest *createChannelNetworkRequest = new CreateChannelNetworkRequest();
				createChannelNetworkRequest->setRequestId(requestId);
				createChannelNetworkRequest->setSender(Config::instance()->getServerName());
				createChannelNetworkRequest->setRequestedChannelName(newChannelName);
				createChannelNetworkRequest->setRequestedChannelOwner(nickName);
				createChannelNetworkRequest->setVoters(networkServerList->size() + 1);
				createChannelNetworkRequest->setLocalClient(localClient);
				createChannelNetworkRequest->addResponse(true);
				networkRequestList->push_back(createChannelNetworkRequest);

				ServerMessagePackage serverMessagePackage(0);
				serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_REQUEST_CHANNEL_CREATE);
				serverMessagePackage.setSender(Config::instance()->getServerName());
				serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_ID, requestId);
				serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_NAME, newChannelName);
				serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_CHANNEL_CREATE_OWNER, nickName);

				performCompleteBroadcast(&serverMessagePackage);
				performResponse(requestId, true);

			}

		}

	} else {

		/* Channel is pending for remove -> unable to join */
		std::string clientText = "Server:> Fail - channel currently unavailable - please try again!\n\r";

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	}

}

void IBRCNetworkManager::processClientLeaveMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();
	NetworkChannel *networkChannel = networkClient->getNetworkChannel();

	/*
	 * Check if client is assigned to a channel
	 */
	if (networkChannel) {

		/* Remove channel of NetworkCLient */
		std::string channelName = networkChannel->getChannelName();
		networkClient->setNetworkChannel(0);

		ServerMessagePackage serverMessagePackage(0);
		serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_CHANNEL_LEAVE);
		serverMessagePackage.setSender(Config::instance()->getServerName());
		serverMessagePackage.setParameter(ServerMessagePackage::CHANNEL_LEAVE_NICK, networkClient->getClientName());

		performCompleteBroadcast(&serverMessagePackage);

		/* Check if channel is empty after we left and request channel remove */
		performChannelRemoveIfEmpty(localClient, networkChannel);

		/*
		 * Inform LocalClient
		 */
		std::string clientText;
		std::ostringstream clientTextStream;
		clientTextStream << "Server:> Left channel: " << channelName << std::endl;
		clientText = clientTextStream.str();

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	} else {

		/*
		 * Inform LocalClient
		 */
		std::string clientText = "Server:> Fail - No channel\n\r";

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	}

}

void IBRCNetworkManager::processClientListMessage(ClientMessagePackage *package) {

	LocalClient *localClient = (LocalClient*) package->getLocalNode();

	std::string clientText;
	std::ostringstream clientTextStream;

	/*
	 * Build string
	 */
	clientTextStream << "Server:> Channel list:" << std::endl;

	for (std::list<NetworkChannel*>::iterator it = networkChannelList->begin(); it != networkChannelList->end(); ++it) {

		NetworkChannel *networkChannel = *it;

		clientTextStream << "Server:>\t" << networkChannel->getChannelName() << std::endl;

	}

	clientText = clientTextStream.str();

	/*
	 * Inform LocalClient
	 */
	ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
	clientMessagePackage->setText(clientText);

	connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

}

void IBRCNetworkManager::processClientNickMessage(ClientMessagePackage *package) {

	LocalClient *localClient = (LocalClient*) package->getLocalNode();

	std::string requestId;
	std::string& requestedNick = package->getParameter(ClientMessagePackage::NICK_REQUESTED_NICK);

	performGenerateRequestId(requestId);

	/*
	 * Generate our response. Positive or negative result depending on
	 * the fact that we already have a pending request for this nick or not.
	 */
	bool requestAccepted = true;

	/* Check the existing clients */
	if (findNetworkClientByName(requestedNick)) {
		requestAccepted = false;
	}

	/* Check the pending requests for the requested nick */
	if (findCreateNickNetworkRequestByName(requestedNick)) {
		requestAccepted = false;
	}

	if (requestAccepted) {

		/* Create a request and add it to the list of pending requests */
		CreateNickNetworkRequest *createNickNetworkRequest = new CreateNickNetworkRequest();
		createNickNetworkRequest->setRequestedNick(requestedNick);
		createNickNetworkRequest->setRequestId(requestId);
		createNickNetworkRequest->setSender(Config::instance()->getServerName());
		createNickNetworkRequest->setVoters(networkServerList->size() + 1);
		createNickNetworkRequest->setLocalClient(localClient);
		createNickNetworkRequest->addResponse(true);
		networkRequestList->push_back(createNickNetworkRequest);

		ServerMessagePackage serverMessagePackage(0);
		serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_REQUEST_NICK_CREATE);
		serverMessagePackage.setSender(Config::instance()->getServerName());
		serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_NICK_CREATE_ID, requestId);
		serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_NICK_CREATE_NAME, requestedNick);

		std::string clientText;
		std::ostringstream clientTextStream;
		clientTextStream << "Server:> Requesting nickname: " << requestedNick << std::endl;
		clientText = clientTextStream.str();

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

		performCompleteBroadcast(&serverMessagePackage);
		performResponse(requestId, true);

	} else {

		/*
		 * Inform LocalClient
		 */
		std::string clientText;
		std::ostringstream clientTextStream;
		clientTextStream << "Server:> Requesting nickname failed: " << requestedNick << std::endl;
		clientText = clientTextStream.str();

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	}

}

void IBRCNetworkManager::processClientPrivateMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();

	std::string& destinationName = package->getParameter(ClientMessagePackage::PRIVMESSAGE_NAME);
	std::string& senderName = networkClient->getClientName();
	std::string& text = package->getText();

	/* Get destination NetworkClient */
	NetworkClient *destinationNetworkClient = findNetworkClientByName(destinationName);
	/* Get destination NetworkServer */
	NetworkServer *destinationNetworkServer = destinationNetworkClient->getNetworkServer();
	/* get sender NetworkClient */
	NetworkClient *senderNetworkClient = findNetworkClientByName(senderName);

	/*
	 * Send message to destination NetworkServer if destination NetworkClient
	 * is assigned to same like sender NetworkClient
	 */
	if (destinationNetworkClient->getNetworkChannel() == senderNetworkClient->getNetworkChannel()) {

		if (destinationNetworkServer == 0) {

			/*
			 * Destination NetworkClient is connected to this server
			 */
			std::list<LocalNode*> *localClientList = connectionManager->getLocalClientList();

			for (std::list<LocalNode*>::iterator it = localClientList->begin(); it != localClientList->end(); ++it) {

				LocalClient *localClient = (LocalClient*) *it;

				if (localClient->getNetworkClient() == destinationNetworkClient) {

					/*
					 * Inform localClient
					 */
					std::string clientText;
					std::ostringstream clientTextStream;
					clientTextStream << senderName << " PRIVAT :> " << text << std::endl;
					clientText = clientTextStream.str();

					ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
					clientMessagePackage->setText(clientText);

					connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

				}

			}

		} else {

			/*
			 * Destination client is connected to a different server than the sender
			 * forward message into destination NetworkServer direction
			 */
			LocalServer *localServer = (LocalServer*) destinationNetworkServer->getLocalNode();

			ServerMessagePackage *serverMessagePackage = new ServerMessagePackage(localServer);
			serverMessagePackage->setMessageType(ServerMessagePackage::TYPE_CHANNEL_PRIVMESSAGE);
			serverMessagePackage->setSender(Config::instance()->getServerName());
			serverMessagePackage->setParameter(ServerMessagePackage::CHANNEL_PRIVMESSAGE_SENDER, senderName);
			serverMessagePackage->setParameter(ServerMessagePackage::CHANNEL_PRIVMESSAGE_NAME, destinationName);
			serverMessagePackage->setText(text);

			connectionManager->pushOutboundMessagePackageList(serverMessagePackage);

		}

	} else {

		/*
		 * Inform localClient
		 */
		std::string clientText;
		std::ostringstream clientTextStream;
		clientTextStream << "Server PRIVAT :> Fail - Channel mismatch" << std::endl;
		clientText = clientTextStream.str();

		ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
		clientMessagePackage->setText(clientText);

		connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

	}

}

void IBRCNetworkManager::processClientQuitMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();
	NetworkChannel *networkChannel = networkClient->getNetworkChannel();

	/* Send NICK_REMOVE to other server */
	ServerMessagePackage serverMessagePackage(0);
	serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_NICK_REMOVE);
	serverMessagePackage.setSender(Config::instance()->getServerName());
	serverMessagePackage.setParameter(ServerMessagePackage::NICK_REMOVE_NAME, networkClient->getClientName());

	performCompleteBroadcast(&serverMessagePackage);

	/* Find NetworkChannel where NetworkClient is registered as owner and set owner of these NetworkChannel to null */
	std::list<NetworkChannel*> channelList;
	findNetworkChannelByOwner(&channelList, networkClient);

	for (std::list<NetworkChannel*>::iterator it = channelList.begin(); it != channelList.end(); ++it) {
		(*it)->setChannelOwner(0);
	}

	/* Remove NetworkClient */
	networkClientList->remove(networkClient);
	delete (networkClient);

	/* Check if any channel is empty after NetworkClient left and remove them if necessary */
	performChannelRemoveIfEmpty(localClient, networkChannel);

	/* Disconnect and remove LocalClient */
	localClient->getTcpConnection()->closeConnection();
	connectionManager->getLocalClientList()->remove(localClient);
	delete(localClient);

}

void IBRCNetworkManager::processClientSettopicMessage(ClientMessagePackage *package) {

	/* Get required information from ClientMessagePackage */
	LocalClient *localClient = (LocalClient*) package->getLocalNode();
	NetworkClient *networkClient = localClient->getNetworkClient();

	std::string clientText;
	NetworkChannel *networkChannel = networkClient->getNetworkChannel();

	/*
	 * Check if NetworkClient is assigned to a channel
	 */
	if (networkChannel) {

		/*
		 * Check if NetworkClient is owner of the channel
		 */
		if (networkChannel->getChannelOwner() == networkClient) {

			std::string& channelTopic = package->getParameter(ClientMessagePackage::SETTOPIC_CHANNEL);
			std::string& channelName = networkChannel->getChannelName();
			networkChannel->setTopic(channelTopic);

			ServerMessagePackage serverMessagePackage(0);
			serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_CHANNEL_SETTOPIC);
			serverMessagePackage.setSender(Config::instance()->getServerName());
			serverMessagePackage.setParameter(ServerMessagePackage::CHANNEL_SETTOPIC_NAME, channelName);
			serverMessagePackage.setParameter(ServerMessagePackage::CHANNEL_SETTOPIC_TOPIC, channelTopic);

			performCompleteBroadcast(&serverMessagePackage);

			clientText = "Server:> Changed channel topic!\n\r";

		} else {
			clientText = "Server:> Fail - You're not the channel owner!\n\r";
		}
	} else {
		clientText = "Server:> Fail - No channel!\n\r";
	}

	ClientMessagePackage *clientMessagePackage = new ClientMessagePackage(localClient);
	clientMessagePackage->setText(clientText);

	connectionManager->pushOutboundMessagePackageList(clientMessagePackage);

}

/***********************************************************************************
 ***********************************************************************************
 *
 *
 *
 * Misc
 *
 *
 *
 ***********************************************************************************
 ***********************************************************************************/

/**
 * Broadcasts a NetworkMessage to every LocalServer except the one it was received from
 */
void IBRCNetworkManager::performForwardBroadcast(ServerMessagePackage *package) {

	/*
	 * Send to parent
	 */
	LocalNode *senderNode = package->getLocalNode();
	LocalNode *parentNode = (LocalNode*) connectionManager->getLocalParentServer();

	if (parentNode && parentNode != senderNode) {

		ServerMessagePackage *newPackage = new ServerMessagePackage(parentNode);
		*newPackage = *package;
		newPackage->setLocalNode(parentNode);
		connectionManager->pushOutboundMessagePackageList(newPackage);

	}

	/*
	 * Send to childs
	 */
	std::list<LocalNode*> *localServerList = connectionManager->getLocalServerList();

	for (std::list<LocalNode*>::iterator it = localServerList->begin(); it != localServerList->end(); ++it) {

		LocalNode *childNode = (*it);

		if (childNode != senderNode) {

			ServerMessagePackage *newPackage = new ServerMessagePackage(childNode);
			*newPackage = *package;
			newPackage->setLocalNode(childNode);
			connectionManager->pushOutboundMessagePackageList(newPackage);

		}

	}

}

/**
 * Broadcasts a NetworkMessage to every LocalServer
 */
void IBRCNetworkManager::performCompleteBroadcast(ServerMessagePackage *package) {

	/*
	 * Send to parent
	 */
	LocalNode *parentNode = (LocalNode*) connectionManager->getLocalParentServer();

	if (parentNode) {

		ServerMessagePackage *newPackage = new ServerMessagePackage(parentNode);
		*newPackage = *package;
		newPackage->setLocalNode(parentNode);
		connectionManager->pushOutboundMessagePackageList(newPackage);

	}

	/*
	 * Send to childs
	 */
	std::list<LocalNode*> *localServerList = connectionManager->getLocalServerList();

	for (std::list<LocalNode*>::iterator it = localServerList->begin(); it != localServerList->end(); ++it) {

		LocalNode *localNode = (*it);

		ServerMessagePackage *newPackage = new ServerMessagePackage(localNode);
		*newPackage = *package;
		newPackage->setLocalNode(localNode);
		connectionManager->pushOutboundMessagePackageList(newPackage);

	}

}

void IBRCNetworkManager::performChannelRemoveIfEmpty(LocalClient *localClient, NetworkChannel *networkChannel) {

	if (networkChannel) {
		/*
		 * Request to remove channel if it's empty
		 */
		std::list<NetworkClient*> clientList;

		findNetworkClientsByChannel(&clientList, networkChannel);

		if (clientList.size() == 0) {

			/*
			 * No channel members left -> request to remove
			 */
			std::string requestId;

			performGenerateRequestId(requestId);

			RemoveChannelNetworkRequest *removeChannelNetworkRequest = new RemoveChannelNetworkRequest();
			removeChannelNetworkRequest->setRequestId(requestId);
			removeChannelNetworkRequest->setSender(Config::instance()->getServerName());
			removeChannelNetworkRequest->setChannelName(networkChannel->getChannelName());
			removeChannelNetworkRequest->setVoters(networkServerList->size() + 1);
			removeChannelNetworkRequest->setLocalClient(localClient);
			removeChannelNetworkRequest->addResponse(true);
			networkRequestList->push_back(removeChannelNetworkRequest);

			ServerMessagePackage serverMessagePackage(0);
			serverMessagePackage.setMessageType(ServerMessagePackage::TYPE_REQUEST_CHANNEL_REMOVE);
			serverMessagePackage.setSender(Config::instance()->getServerName());
			serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_CHANNEL_REMOVE_ID, requestId);
			serverMessagePackage.setParameter(ServerMessagePackage::REQUEST_CHANNEL_REMOVE_NAME, networkChannel->getChannelName());

			performCompleteBroadcast(&serverMessagePackage);
			performResponse(requestId, true);

		}
	}

}

void IBRCNetworkManager::performGenerateRequestId(std::string& requestId) {

	std::stringstream ss;

	ss << Config::instance()->getServerName() << requestIdNumber++;
	requestId = ss.str();
}

void IBRCNetworkManager::performGenerateDefaultNick(std::string& defaultNick) {

	std::stringstream ss;

	ss << Config::instance()->getServerName() << "_client" << defaultNickNumber++;
	defaultNick = ss.str();
}

void IBRCNetworkManager::performResponse(std::string& requestId, bool value) {

	/* Create a response package and broadcast it to every connected server */
	ServerMessagePackage responsePackage(0);
	responsePackage.setMessageType(ServerMessagePackage::TYPE_RESPONSE);
	responsePackage.setSender(Config::instance()->getServerName());
	responsePackage.setParameter(ServerMessagePackage::RESPONSE_ID, requestId);
	responsePackage.setParameter(ServerMessagePackage::RESPONSE_VALUE, ((value) ? "true" : "false"));

	performCompleteBroadcast(&responsePackage);

}

std::list<NetworkServer*> *IBRCNetworkManager::getNetworkServerList() {
	return networkServerList;
}

std::list<NetworkClient*> *IBRCNetworkManager::getNetworkClientList() {
	return networkClientList;
}

std::list<NetworkChannel*> *IBRCNetworkManager::getNetworkChannelList() {
	return networkChannelList;
}

std::list<NetworkRequest*> *IBRCNetworkManager::getNetworkRequestList() {
	return networkRequestList;
}

/***********************************************************************************
 ***********************************************************************************
 *
 *
 *
 * List finders
 *
 *
 *
 ***********************************************************************************
 ***********************************************************************************/

NetworkRequest *IBRCNetworkManager::findNetworkRequestById(std::string& id) {

	for (std::list<NetworkRequest*>::iterator it = networkRequestList->begin(); it != networkRequestList->end(); ++it) {

		NetworkRequest *networkRequest = *it;

		if (!networkRequest->getRequestId().compare(id)) {
			return networkRequest;
		}

	}

	return 0;
}

RemoveChannelNetworkRequest *IBRCNetworkManager::findRemoveChannelNetworkRequestByName(std::string& name){

	RemoveChannelNetworkRequest *removeChannelNetworkRequest = 0;

	for(std::list<NetworkRequest*>::iterator it = networkRequestList->begin(); it != networkRequestList->end(); ++it){

		if((*it)->getNetworkRequestType() == NetworkRequest::CHANNEL_REMOVE_REQUEST){

			if(!((RemoveChannelNetworkRequest*)(*it))->getChannelName().compare(name)){
				removeChannelNetworkRequest = (RemoveChannelNetworkRequest*)(*it);
			}
		}

	}

	return removeChannelNetworkRequest;
}

NetworkClient *IBRCNetworkManager::findNetworkClientByName(std::string& name) {

	for (std::list<NetworkClient*>::iterator it = networkClientList->begin(); it != networkClientList->end(); ++it) {

		NetworkClient *networkClient = *it;

		if (!networkClient->getClientName().compare(name)) {
			return networkClient;
		}

	}

	return 0;
}

void IBRCNetworkManager::findNetworkClientsByChannel(std::list<NetworkClient*> *clientList, NetworkChannel *networkChannel) {

	for (std::list<NetworkClient*>::iterator it = networkClientList->begin(); it != networkClientList->end(); ++it) {

		NetworkClient *networkClient = *it;

		if (networkClient->getNetworkChannel() == networkChannel) {
			clientList->push_back(networkClient);
		}

	}
}

NetworkChannel *IBRCNetworkManager::findNetworkChannelByName(std::string& name) {

	for (std::list<NetworkChannel*>::iterator it = networkChannelList->begin(); it != networkChannelList->end(); ++it) {

		NetworkChannel *networkChannel = *it;

		if (!networkChannel->getChannelName().compare(name)) {
			return networkChannel;
		}

	}

	return 0;
}

void IBRCNetworkManager::findNetworkChannelByOwner(std::list<NetworkChannel*> *channelList, NetworkClient *networkClient) {

	for (std::list<NetworkChannel*>::iterator it = networkChannelList->begin(); it != networkChannelList->end(); ++it) {

		NetworkChannel *networkChannel = *it;

		if (networkChannel->getChannelOwner() == networkClient) {
			channelList->push_back(networkChannel);
		}

	}

}

NetworkServer *IBRCNetworkManager::findNetworkServerByName(std::string& name) {

	for (std::list<NetworkServer*>::iterator it = networkServerList->begin(); it != networkServerList->end(); ++it) {

		NetworkServer *networkServer = *it;

		if (!networkServer->getServerName().compare(name)) {
			return networkServer;
		}

	}

	return 0;
}

void IBRCNetworkManager::findNetworkServerByClients(std::list<NetworkServer*> *serverList, std::list<NetworkClient*> *clientList) {

	for (std::list<NetworkClient*>::iterator it = clientList->begin(); it != clientList->end(); ++it) {

		NetworkClient *networkClient = *it;
		NetworkServer *networkServer = networkClient->getNetworkServer();

		if (networkServer) {

			bool serverFoundInList = false;

			for (std::list<NetworkServer*>::iterator it = serverList->begin(); it != serverList->end(); ++it) {

				if (*it == networkServer) {
					serverFoundInList = true;
					break;
				}

			}

			if (!serverFoundInList) {
				serverList->push_back(networkServer);
			}

		}

	}

}

void IBRCNetworkManager::findLocalServerByNetworkServer(std::list<LocalServer*> *localServerList, std::list<NetworkServer*> *networkServerList) {

	for (std::list<NetworkServer*>::iterator it = networkServerList->begin(); it != networkServerList->end(); ++it) {

		NetworkServer *networkServer = *it;
		LocalServer *localServer = (LocalServer*) networkServer->getLocalNode();

		if (localServer) {

			bool serverFoundInList = false;

			for (std::list<LocalServer*>::iterator it = localServerList->begin(); it != localServerList->end(); ++it) {

				if (*it == localServer) {
					serverFoundInList = true;
					break;
				}

			}

			if (!serverFoundInList) {
				localServerList->push_back(localServer);
			}

		}

	}

}

CreateChannelNetworkRequest *IBRCNetworkManager::findCreateChannelNetworkRequestByName(std::string& name) {

	for (std::list<NetworkRequest*>::iterator it = networkRequestList->begin(); it != networkRequestList->end(); ++it) {

		CreateChannelNetworkRequest *networkRequest = (CreateChannelNetworkRequest*) *it;

		if (networkRequest->getNetworkRequestType() == NetworkRequest::CHANNEL_CREATE_REQUEST) {

			std::string& networkRequestClientName = networkRequest->getRequestedChannelName();

			if (!networkRequestClientName.compare(name)) {
				return networkRequest;
			}

		}

	}

	return 0;
}

CreateNickNetworkRequest *IBRCNetworkManager::findCreateNickNetworkRequestByName(std::string& name) {

	for (std::list<NetworkRequest*>::iterator it = networkRequestList->begin(); it != networkRequestList->end(); ++it) {

		CreateNickNetworkRequest *networkRequest = (CreateNickNetworkRequest*) *it;

		if (networkRequest->getNetworkRequestType() == NetworkRequest::NICK_REQUEST) {

			std::string& networkRequestClientName = networkRequest->getRequestedNick();

			if (!networkRequestClientName.compare(name)) {
				return networkRequest;
			}

		}

	}

	return 0;
}
